package main

import "fmt"

/*
	结构体的匿名字段：
		结构体允许其成员字段在声明时没有字段名而只有类型，这种没有名字的字短就称为匿名字段
		匿名字段默认采用类型名作为字段名
		机构体要求字段名必须唯一，因此一个结构体中同种类型的匿名字段只能有一个, 且类型不能重复

	结构体的字段类型：
		结构体的字段类型可以是：基本数据类型、切片、Map以及结构体
		如果结构体的字段类型是：指针、slice和map，初始值都为nil，即还没有分配空间。则需要先make(指针new)才能使用
*/

// Person1 描述人的结构体
type Person1 struct {
	string
	int
}

// Person 描述人的结构体
type Person struct {
	Name      string
	Age       int
	Hobby     []string
	OtherInfo map[string]string
}

// User 描述账号
type User struct {
	Username string
	Password string

	// // 嵌套实名Address结构体
	// Address Address
	// Email Email

	// 嵌套匿名结构体
	Address
	*Email
}

// Address 收货地址
type Address struct {
	City    string
	Area    string
	Block   string
	AddTime string
}

// Email 邮箱
type Email struct {
	Host    string
	Addr    string
	AddTime string
}

func main() {
	// // 匿名字段默认采用类型名作为字段名
	// p := Person{
	// 	"张三",
	// 	20,
	// }
	// fmt.Println(p.string)
	// fmt.Println(p.int)
	// fmt.Println(p)

	// // 结构体字段
	// var p Person
	// p.Name = "张三"
	// p.Age = 20
	// // 切片需要先分配空间才能使用
	// p.Hobby = make([]string, 3, 6)
	// p.Hobby[0] = "打篮球"
	// p.Hobby[1] = "睡觉"
	// // Map类型也需要先分配空间才能使用
	// p.OtherInfo = make(map[string]string, 3)
	// p.OtherInfo["height"] = "180cm"
	// p.OtherInfo["weight"] = "70kg"
	// fmt.Printf("%#v", p)

	// 结构体嵌套
	var u1 User
	u1.Username = "Mike"
	u1.Password = "123"
	var addr1 = Address{
		City:  "西虹市",
		Area:  "炒蛋区",
		Block: "",
	}
	var email1 = Email{}
	u1.Address = addr1
	fmt.Printf("%#v\n", u1)
	u1.Address.Block = "下饭街"
	u1.Address.AddTime = "2020-01-01"
	u1.Email = &email1 // 嵌套结构体可以传结构体指针
	u1.Email.AddTime = "2020-12-31"
	fmt.Printf("%#v\n", u1)
	fmt.Println(u1.Address.Block)

	// 结构体可以直接访问内部结构体中的字段
	// 访问结构体字段首先会在结构体中查找该字段，找不到再去匿名嵌套结构体中查找
	fmt.Println(u1.Area)

	// 结构体的字段命名冲突
	// 主结构体通过"."直接访问多个子结构中共有的同名字段会报错
	// fmt.Println(u1.AddTime)
	fmt.Println(u1.Email.AddTime)
	fmt.Println(u1.Address.AddTime)
}
